package com.tencent.wxpay.business;

import com.tencent.wxpay.businessListener.BaseResultListener;
import com.tencent.wxpay.common.Configure;
import com.tencent.wxpay.common.Signature;
import com.tencent.wxpay.common.Util;
import com.tencent.wxpay.common.XMLParser;
import com.tencent.wxpay.common.report.ReporterFactory;
import com.tencent.wxpay.common.report.protocol.ReportReqData;
import com.tencent.wxpay.common.report.service.ReportService;
import com.tencent.wxpay.protocol.request.RefundQueryReqData;
import com.tencent.wxpay.protocol.response.RefundQueryResData;
import com.tencent.wxpay.service.RefundQueryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 退款查询服务
 */
public class RefundQueryBusiness {

    private static final Logger logger = LoggerFactory.getLogger(RefundQueryBusiness.class);

    /**
     * 运行退款查询的业务逻辑
     * @param refundQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
     * @param resultListener 商户需要自己监听退款查询业务逻辑可能触发的各种分支事件，并做好合理的响应处理
     * @return RefundQueryResData 返回的数据对象
     * @throws Exception
     */
    public static RefundQueryResData run(RefundQueryReqData refundQueryReqData, BaseResultListener<RefundQueryResData> resultListener) throws Exception {
        //--------------------------------------------------------------------
        //构造请求“退款查询API”所需要提交的数据
        //--------------------------------------------------------------------
        RefundQueryService refundQueryService = new RefundQueryService();
        String outTradeNo = refundQueryReqData.getOut_trade_no();
        //接收API返回
        String refundQueryServiceResponseString;
        // API调用开始时间
        long costTimeStart = System.currentTimeMillis();
        // 发起请求
        refundQueryServiceResponseString = refundQueryService.request(refundQueryReqData);
        // API调用结束时间
        long costTimeEnd = System.currentTimeMillis();
        // API请求耗费时间
        long totalTimeCost = costTimeEnd - costTimeStart;
        logger.info("退款查询接口，【订单号："+outTradeNo+"】请求总耗时：" + totalTimeCost + "ms");
        //打印回包数据
        logger.info("退款查询接口,【订单号："+outTradeNo+"】 回包数据:");
        logger.info(refundQueryServiceResponseString);

        //将从API返回的XML数据映射到Java对象
        RefundQueryResData refundQueryResData = (RefundQueryResData) Util.getObjectFromXML(refundQueryServiceResponseString, RefundQueryResData.class);
        //是否发送统计请求
        if(Configure.isReport()) {
            ReportReqData reportReqData = new ReportReqData(
                refundQueryReqData.getDevice_info(),
                Configure.REFUND_QUERY_API,
                (int) (totalTimeCost),//本次请求耗时
                refundQueryResData.getReturn_code(),
                refundQueryResData.getReturn_msg(),
                refundQueryResData.getResult_code(),
                refundQueryResData.getErr_code(),
                refundQueryResData.getErr_code_des(),
                refundQueryResData.getOut_trade_no(),
                Configure.getIP()
            );
            // refundQuery+report总耗时
            long timeAfterReport;
            // 判断是否异步发送
            if (Configure.isUseThreadToDoReport()) {
                ReporterFactory.getReporter(reportReqData).run();
                timeAfterReport = System.currentTimeMillis();
                logger.info("【订单号："+outTradeNo+"】refundQuery+report总耗时（异步方式上报）：" + (timeAfterReport - costTimeStart) + "ms");
            } else {
                ReportService.request(reportReqData);
                timeAfterReport = System.currentTimeMillis();
                logger.info("【订单号："+outTradeNo+"】refundQuery+report总耗时（同步方式上报）：" + (timeAfterReport - costTimeStart) + "ms");
            }
        }
        // API通信失败
        if (refundQueryResData == null || refundQueryResData.getReturn_code() == null) {
            logger.error("【退款查询失败】【订单号："+outTradeNo+"】退款查询API请求逻辑错误，请仔细检测传过去的每一个参数是否合法，或是看API能否被正常访问");
            resultListener.onFailByReturnCodeError(refundQueryResData);
            return refundQueryResData;
        }
        // API通信成功，但调用出错，可能签名失败或参数格式校验错误
        if (refundQueryResData.getReturn_code().equals("FAIL")) {
            ///注意：一般这里返回FAIL是出现系统级参数错误，请检测Post给API的数据是否规范合法
            logger.error("【退款查询失败】【订单号："+outTradeNo+"】退款查询API系统返回失败，请检测Post给API的数据是否规范合法");
            resultListener.onFailByReturnCodeFail(refundQueryResData);
            return refundQueryResData;
        } else {
            logger.info("退款查询接口【订单号："+outTradeNo+"】成功返回数据");
            //--------------------------------------------------------------------
            //收到API的返回数据的时候得先验证一下数据有没有被第三方篡改，确保安全
            //--------------------------------------------------------------------
            if (!Signature.checkIsSignValidFromResponseString(refundQueryServiceResponseString)) {
                logger.error("【退款查询失败】【订单号："+outTradeNo+"】退款查询API返回的数据签名验证失败，有可能数据被篡改了");
                resultListener.onFailBySignInvalid(refundQueryResData);
                return refundQueryResData;
            }

            if (refundQueryResData.getResult_code().equals("FAIL")) {
                logger.error("【退款查询失败】【订单号："+outTradeNo+"】");
                logger.error("错误码：" + refundQueryResData.getErr_code());
                logger.error("错误信息：" + refundQueryResData.getErr_code_des());
                resultListener.onFail(refundQueryResData);
                //退款失败时再怎么延时查询退款状态都没有意义，这个时间建议要么再手动重试一次，依然失败的话请走投诉渠道进行投诉
            } else {
                //退款成功
                refundQueryResData.setRefundQueries(XMLParser.getRefundQueryList(refundQueryServiceResponseString));
                logger.info("【退款查询成功】【订单号："+outTradeNo+"】");
                resultListener.onSuccess(refundQueryResData);
            }
        }
        return refundQueryResData;
    }
}
